home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 8 / Night Owl CD-ROM (NOPV8) (Night Owl Publisher) (1993).ISO / 017a / binutils.arj / SIZE.C < prev    next >
C/C++ Source or Header  |  1991-03-27  |  9KB  |  402 lines

  1. /* Size of rel file utility (`size') for GNU.
  2.    Copyright (C) 1986 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 1, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. #include <stdio.h>
  19. #include <ar.h>
  20. #include <sys/types.h>
  21. #include <sys/file.h>
  22.  
  23. #if !defined(A_OUT) && !defined(MACH_O)
  24. #define A_OUT
  25. #endif
  26.  
  27. #ifdef A_OUT
  28. #ifdef COFF_ENCAPSULATE
  29. #ifdef GNUDOS
  30. #include "aoutencap.h"
  31. #else
  32. #include "a.out.encap.h"
  33. #endif
  34. #else
  35. /* On native BSD systems, use the system's own a.out.h.  */
  36. #ifdef GNUDOS
  37. #include <aout.h>
  38. #else
  39. #include <a.out.h>
  40. #endif
  41. #endif
  42. #endif
  43.  
  44. #ifdef MACH_O
  45. #include <sys/loader.h>
  46. #endif
  47.  
  48. #ifdef USG
  49. #include <fcntl.h>
  50. #include <string.h>
  51. #else
  52. #include <strings.h>
  53. #endif
  54.  
  55. /* Number of input file names specified.  */
  56.  
  57. int number_of_files;
  58.  
  59. /* Current file's name */
  60.  
  61. char *input_name;
  62.  
  63. /* Current member's name, or 0 if processing a non-library file.  */
  64.  
  65. char *input_member;
  66.  
  67. /* Offset within archive of the current member,
  68.    if we are processing an archive.  */
  69.  
  70. int member_offset;
  71.  
  72. #ifndef GNUDOS
  73. char *malloc ();
  74. #endif
  75.  
  76. void do_one_file (), do_one_rel_file ();
  77. char *xmalloc ();
  78. char *concat ();
  79.  
  80. main (argc, argv)
  81.      char **argv;
  82.      int argc;
  83. {
  84.   int i;
  85.  
  86. #ifdef GNUDOS
  87.   _fmode = O_BINARY; /* set default file type */
  88. #endif
  89.  
  90.   number_of_files = argc - 1;
  91.  
  92.   printf ("text\tdata\tbss\tdec\thex\n");
  93.  
  94.   /* Now scan and describe the files.  */
  95.  
  96.   if (number_of_files == 0)
  97.     do_one_file ("a.out");
  98.   else
  99.     for (i = 1; i < argc; i++)
  100.       do_one_file (argv[i]);
  101.   exit (0);
  102. }
  103.  
  104. /* Print the filename of the current file on 'outfile' (a stdio stream).  */
  105.  
  106. print_file_name (outfile)
  107.      FILE *outfile;
  108. {
  109.   fprintf (outfile, "%s", input_name);
  110.   if (input_member)
  111.     fprintf (outfile, "(%s)", input_member);
  112. }
  113.  
  114. /* process one input file */
  115. void scan_library ();
  116.  
  117. void
  118. do_one_file (name)
  119.      char *name;
  120. {
  121.   int len, desc;
  122.   char armag[SARMAG];
  123.  
  124.   desc = open (name, O_RDONLY, 0);
  125.  
  126.   if (desc < 0)
  127.     {
  128.       perror_name (name);
  129.       return;
  130.     }
  131.  
  132.   input_name = name;
  133.   input_member = 0;
  134.  
  135.   if (SARMAG != read (desc, armag, SARMAG) || strncmp (armag, ARMAG, SARMAG))
  136.     do_one_rel_file (desc, 0L);
  137.   else
  138.     scan_library (desc);
  139.  
  140.   close (desc);
  141. }
  142.  
  143. /* Read in the archive data about one member.
  144.    subfile_offset is the address within the archive of the start of that data.
  145.    The value returned is the length of the member's contents, which does
  146.    not include the archive data about the member.
  147.  
  148.    If there are no more valid members, zero is returned.  */
  149.  
  150. int
  151. decode_library_subfile (desc, subfile_offset)
  152.      int desc;
  153.      int subfile_offset;
  154. {
  155.   int bytes_read;
  156.   int namelen;
  157.   int member_length;
  158.   char *name;
  159.   struct ar_hdr hdr1;
  160.  
  161.   lseek (desc, subfile_offset, 0);
  162.  
  163.   bytes_read = read (desc, &hdr1, sizeof hdr1);
  164.   if (!bytes_read)
  165.     ;        /* end of archive */
  166.  
  167.   else if (sizeof hdr1 != bytes_read)
  168.     error_with_file ("malformed library archive");
  169.  
  170.   else if (sscanf (hdr1.ar_size, "%d", &member_length) != 1)
  171.     error_with_file ("malformatted header of archive member");
  172.  
  173.   else
  174.     {
  175.       for (namelen = 0;
  176.        hdr1.ar_name[namelen] != 0
  177.        && hdr1.ar_name[namelen] != ' '
  178.        && hdr1.ar_name[namelen] != '/';
  179.        namelen++)
  180.     ;
  181.       name = (char *) xmalloc (namelen+1);
  182.       strncpy (name, hdr1.ar_name, namelen);
  183.       *(name + namelen) = 0;
  184.  
  185.       input_member = name;
  186.  
  187.       return member_length;
  188.     }
  189.   return 0;   /* tell caller to exit loop */
  190. }
  191.  
  192. /* Scan a library and describe each member.  */
  193.  
  194. void
  195. scan_library (desc)
  196.      int desc;
  197. {
  198.   int this_subfile_offset = SARMAG;
  199.   int member_length;
  200.   
  201.   while (member_length = decode_library_subfile (desc, this_subfile_offset))
  202.     {
  203.       /* describe every member except the ranlib data if any */
  204.       if (strcmp (input_member, "__.SYMDEF"))
  205.     do_one_rel_file (desc, this_subfile_offset + sizeof (struct ar_hdr));
  206.  
  207.       this_subfile_offset += ((member_length + sizeof (struct ar_hdr)) + 1) & -2;
  208.     }
  209. }
  210.  
  211. /* Read a file's header and fill in various pieces of information.
  212.    Return 0 on failure.  */
  213.  
  214. int
  215. read_header_info (desc, offset, tsize, dsize, bsize)
  216.      int desc;
  217.      long int offset;
  218.      unsigned int *tsize;
  219.      unsigned int *dsize;
  220.      unsigned int *bsize;
  221. {
  222.   int len;
  223.  
  224. #ifdef A_OUT
  225.   {
  226.     struct exec hdr;
  227.  
  228.     lseek (desc, offset, 0);
  229. #ifdef HEADER_SEEK_FD
  230.     /* Skip the headers that encapsulate our data in some other format
  231.        such as COFF.  */
  232.     HEADER_SEEK_FD (desc);
  233. #endif
  234.     len = read (desc, (char *) &hdr, sizeof (struct exec));
  235.     if (len == sizeof (struct exec) && !N_BADMAG (hdr))
  236.       {
  237.     *tsize = hdr.a_text;
  238.     *dsize = hdr.a_data;
  239.     *bsize = hdr.a_bss;
  240.     return 1;
  241.       }
  242.   }
  243. #endif
  244.  
  245. #ifdef MACH_O
  246.   {
  247.     struct mach_header mach_header;
  248.     char *hdrbuf;
  249.     struct load_command *load_command;
  250.     struct segment_command *segment_command;
  251.     struct section *section;
  252.     int len, cmd, seg;
  253.  
  254.     lseek (desc, offset, 0);
  255.     len = read (desc, (char *) &mach_header, sizeof (struct mach_header));
  256.     if (len == sizeof (struct mach_header) && mach_header.magic == MH_MAGIC)
  257.       {
  258.     hdrbuf = xmalloc (mach_header.sizeofcmds);
  259.     len = read (desc, hdrbuf, mach_header.sizeofcmds);
  260.     if (len != mach_header.sizeofcmds)
  261.       {
  262.         error_with_file ("failure reading Mach-O load commands");
  263.         return 0;
  264.       }
  265.     load_command = (struct load_command *) hdrbuf;
  266.     for (cmd = 0; cmd < mach_header.ncmds; ++cmd)
  267.       {
  268.         if (load_command->cmd == LC_SEGMENT)
  269.           {
  270.         segment_command = (struct segment_command *) load_command;
  271.         section = (struct section *) ((char *) (segment_command + 1));
  272.         for (seg = 0; seg < segment_command->nsects; ++seg, ++section)
  273.           {
  274.             if (!strncmp(SECT_TEXT, section->sectname, sizeof section->sectname))
  275.               *tsize = section->size;
  276.             else if (!strncmp(SECT_DATA, section->sectname, sizeof section->sectname))
  277.               *dsize = section->size;
  278.             else if (!strncmp(SECT_BSS, section->sectname, sizeof section->sectname))
  279.               *bsize = section->size;
  280.           }
  281.           }
  282.         load_command = (struct load_command *)
  283.           ((char *) load_command + load_command->cmdsize);
  284.       }
  285.     free (hdrbuf);
  286.     return 1;
  287.       }
  288.   }
  289. #endif
  290.  
  291.   return 0;
  292. }
  293.  
  294. void
  295. do_one_rel_file (desc, offset)
  296.      int desc;
  297.      long int offset;
  298. {
  299.   unsigned int tsize, dsize, bsize, total;
  300.  
  301.   if (read_header_info (desc, offset, &tsize, &dsize, &bsize))
  302.     {
  303.       total =  tsize + dsize + bsize;
  304.       printf ("%u\t%u\t%u\t%u\t%x", tsize, dsize, bsize, total, total);
  305.     }
  306.   else
  307.     {
  308.       error_with_file ("malformed input file (not rel or archive)");
  309.       return;
  310.     }
  311.  
  312.   if (number_of_files > 1 || input_member)
  313.     {
  314.       printf ("\t");
  315.       print_file_name (stdout);
  316.     }
  317.   printf ("\n");
  318. }
  319.  
  320. /* Report a fatal error.
  321.    STRING is a printf format string and ARG is one arg for it.  */
  322.  
  323. fatal (string, arg)
  324.      char *string, *arg;
  325. {
  326.   fprintf (stderr, "size: ");
  327.   fprintf (stderr, string, arg);
  328.   fprintf (stderr, "\n");
  329.   exit (1);
  330. }
  331.  
  332. /* Report a nonfatal error.
  333.    STRING is a printf format string and ARG is one arg for it.  */
  334.  
  335. error (string, arg)
  336.      char *string, *arg;
  337. {
  338.   fprintf (stderr, "size: ");
  339.   fprintf (stderr, string, arg);
  340.   fprintf (stderr, "\n");
  341. }
  342.  
  343. /* Report a nonfatal error.
  344.    STRING is printed, followed by the current file name.  */
  345.  
  346. error_with_file (string)
  347.      char *string;
  348. {
  349.   fprintf (stderr, "size: ");
  350.   print_file_name (stderr);
  351.   fprintf (stderr, ": ");
  352.   fprintf (stderr, string);
  353.   fprintf (stderr, "\n");
  354. }
  355.  
  356. /* Report an error using the message for the last failed system call,
  357.    followed by the string NAME.  */
  358.  
  359. perror_name (name)
  360.      char *name;
  361. {
  362.   extern int errno, sys_nerr;
  363.   extern char *sys_errlist[];
  364.   char *s;
  365.  
  366.   if (errno < sys_nerr)
  367.     s = concat (name, ": ", sys_errlist[errno]);
  368.   else
  369.     s = concat (name, ": ", "unknown error");
  370.   error (s, name);
  371. }
  372.  
  373. /* Like malloc but get fatal error if memory is exhausted.  */
  374.  
  375. char *
  376. xmalloc (size)
  377.      int size;
  378. {
  379.   char *result = malloc (size);
  380.   if (!result)
  381.     fatal ("virtual memory exhausted", 0);
  382.   return result;
  383. }
  384.  
  385. /* Return a newly-allocated string
  386.    whose contents concatenate those of S1, S2, S3.  */
  387.  
  388. char *
  389. concat (s1, s2, s3)
  390.      char *s1, *s2, *s3;
  391. {
  392.   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  393.   char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
  394.  
  395.   strcpy (result, s1);
  396.   strcpy (result + len1, s2);
  397.   strcpy (result + len1 + len2, s3);
  398.   result[len1 + len2 + len3] = 0;
  399.  
  400.   return result;
  401. }
  402.